package org.yiming.tools.mqtt.client.cli;

import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.yiming.tools.mqtt.client.ApplicationContext;
import org.yiming.tools.mqtt.client.client.MqttClient;
import org.yiming.tools.mqtt.client.utils.ConsoleUtil;
import org.yiming.tools.mqtt.client.utils.IoUtil;

import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author renwenpeng
 * date  2022/3/21 4:08 下午
 */
@Slf4j
public final class Application {
    private Application() {

    }

    private static final String COMMAND_QUIT_FLAG = "q\n";
    private static final String COMMAND_FORCE_QUIT_FLAG = "fq\n";
    private static final String COMMAND_BEGIN_CMD_FLAG = "\n";

    private static final boolean[] FORCE_QUIT_ING = new boolean[]{false};

    public static void run(ApplicationContext applicationContext) {
        run(applicationContext, null);
    }

    public static void run(ApplicationContext applicationContext, Callable<?> callable) {
        // 1）初始化
        applicationContext.init();
        // 2）开始启动连接mqtt服务
        CountDownLatch countDownLatchConn = startMqttClient(applicationContext);
        // 3）加入结束钩子
        addShutdownHooks(applicationContext);

        try {
            // 4）等待初始化成功
            countDownLatchConn.await();
            log.info("application init successful");
            if (callable != null) {
                callable.call();
            }
            // 5）循环读取控制台输入
            startConsoleListener(applicationContext);
        } catch (Exception e) {
            log.error("", e);
            Thread.currentThread().interrupt();
        }

        // 6）退出系统
        log.info("application is shutting down, wait a moment ...");
        System.exit(0);
    }

    private static void addShutdownHooks(ApplicationContext applicationContext) {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            // 8）执行结束时必要操作
            if (!FORCE_QUIT_ING[0]) {
                applicationContext.getMqttClientMap().forEach(((s, mqttClient) -> {
                    try {
                        // 关闭连接
                        mqttClient.close();
                    } catch (MqttException e) {
                        log.error("close error", e);
                    }
                }));
            }
            countDownLatch.countDown();
        }));
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            // 9）等待结束
            StringBuilder stringBuilder = new StringBuilder();
            while (countDownLatch.getCount() != 0) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                    stringBuilder.append(".");
                    log.info(stringBuilder.toString());
                } catch (InterruptedException e) {
                    log.error("", e);
                    Thread.currentThread().interrupt();
                }
            }
            // 10）成功结束
            log.info("application over");
        }));
    }

    private static void startConsoleListener(ApplicationContext applicationContext) {
        boolean[] isLoop = new boolean[]{true};
        do {
            IoUtil.inputStream(System.in, inputString -> {
                // 退出
                if (isQuit(inputString)) {
                    isLoop[0] = false;
                    return false;
                }
                if (isForceQuit(inputString)) {
                    isLoop[0] = false;
                    FORCE_QUIT_ING[0] = true;
                    return false;
                }
                // 执行命令
                executeCommand(applicationContext, inputString);
                return true;
            });
        } while (isLoop[0]);
    }

    private static CountDownLatch startMqttClient(ApplicationContext applicationContext) {
        Collection<MqttClient> mqttClients = applicationContext.getMqttClientMap().values();
        CountDownLatch countDownLatchConn = new CountDownLatch(mqttClients.size());
        mqttClients.forEach(mqttClient -> mqttClient.init(countDownLatchConn));
        return countDownLatchConn;
    }

    private static void executeCommand(ApplicationContext applicationContext, String inputString){
        if (COMMAND_BEGIN_CMD_FLAG.equals(inputString)) {
            ConsoleUtil.keySthInStart();
        } else {
            if (ConsoleUtil.isIsKeySthIn()) {
                ConsoleUtil.keySthInStop();
                // 去掉\n
                String execute = applicationContext.getCommandDispatcher()
                        .execute(inputString.substring(0, inputString.length() - 1));
                if (execute != null) {
                    log.info(execute);
                }
            }
        }
    }

    private static boolean isQuit(String inputString) {
        return ConsoleUtil.isIsKeySthIn()
                && (inputString == null || COMMAND_QUIT_FLAG.equals(inputString));
    }

    private static boolean isForceQuit(String inputString) {
        return ConsoleUtil.isIsKeySthIn()
                && (inputString == null || COMMAND_FORCE_QUIT_FLAG.equals(inputString));
    }
}
